/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现本地化管理器的主要逻辑
* 实现多国语言的本地加载、解析、切换等功能
* CreateTime：2020-04-07 16:28:43
* Version：1.0
* Modify Recorder：
*************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TinyToolKit.AssetLoad;
using UnityEngine;

namespace TinyToolKit.Localization
{
    public class TLocalizationManager : ManagerBase, ILocalizationManager
    {
        public event Action OnLanguageChanged;
        public event Action OnLanguageChangedLater;
        public int transCount => _lanTranslation.Count;
        
        public Language SystemLanguage => GetSystemLan();
        public Language Language
        {
            get => _curLanguage;
            set
            {
                if (value == Language.Unspecified) TLogTool.Error("请先指定具体的语言类型");
                _curLanguage = value;
            }
        }

        private Dictionary<string, string> _lanTranslation;
        public Dictionary<string, string> CurLanTranslation() => _lanTranslation;

        private Language _curLanguage;

        //存储已经加载好的翻译配置表，key是配置表的路径，value是配置表的内容
        private Dictionary<Language, string> _allTranslations;
        private TResourcesManager _resourcesManager;

        #region ManagerBase
        public override void Init()
        {
            _lanTranslation = new Dictionary<string, string>();
            _allTranslations = new Dictionary<Language, string>();
            _curLanguage = Language.Unspecified;
            OnLanguageChanged = null;
            _resourcesManager = TinyTool.Instance.GetManager<TResourcesManager>();
        }

        public override void UpdateManager()
        {
        }

        public override void Shutdown()
        {
            _curLanguage = Language.Unspecified;
            _lanTranslation.Clear();
            _allTranslations.Clear();
        }
        #endregion

        #region Public Func
        /// <summary>
        /// 自定义模式下，设置翻译配置表
        /// </summary>
        /// <param name="lan">语言类型</param>
        /// <param name="jsonMsg">Json配置表</param> 
        public void SetLanTranslates(Language lan, string jsonMsg)
        {
            if (_allTranslations.ContainsKey(lan) == false)
                _allTranslations.Add(lan, jsonMsg);
        }

        /// <summary>
        /// 切换至本机系统语言
        /// </summary>
        /// <returns>返回是否切换成功</returns>
        public bool ChangeSystemLanguage()
        {
            return ChangeLanguage(SystemLanguage);
        }

        /// <summary>
        /// 切换至指定语言
        /// </summary>
        /// <param name="lan">需要切换的语言类型</param>
        /// <returns>返回是否切换成功</returns>
        public bool ChangeLanguage(Language lan)
        {
            if (Language == lan)
            {
                TLogTool.Info("当前应用语言就是：" + Enum.GetName(typeof(Language), lan));
                return false;
            }

            if (TinyTool.Instance != null && TinyTool.Instance.TinyToolSetting != null)
            {
                if (_allTranslations.ContainsKey(lan))
                {
                    ParseTranslationJson(_allTranslations[lan]);
                    return true;
                }

                LanLocalization[] localizationPaths = TinyTool.Instance.TinyToolSetting.localizationPaths;
                for (int i = 0; i < localizationPaths.Length; i++)
                {
                    if (localizationPaths[i].lan == lan)
                    {
                        LoadLocalizationFile(lan, localizationPaths[i].path);
                        return true;
                    }
                }

                TLogTool.Error(Enum.GetName(typeof(Language), lan) + " 未找到配置文件");
            }
            else
                TLogTool.Error("TinyTool.Instance 或 TinyToolSetting资源为Null");

            return false;
        }

        /// <summary>
        /// 根据关键词判断是否存在该翻译
        /// </summary>
        /// <param name="key">关键词</param>
        /// <returns>返回是否存在</returns>
        public bool HasTranslation(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                TLogTool.Error("Key值不能为Null");
                return false;
            }

            return _lanTranslation.ContainsKey(key);
        }

        /// <summary>
        /// 根据关键词得到该翻译
        /// </summary>
        /// <param name="key">关键词</param>
        /// <returns>返回关键词对应的翻译</returns>
        public string GetTranslation(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                TLogTool.Error("Key值不能为Null");
                return string.Empty;
            }

            if (_lanTranslation.TryGetValue(key, out var value))
            {
                return value;
            }

            return string.Empty;
        }

        /// <summary>
        /// 添加翻译
        /// </summary>
        /// <param name="key">关键词</param>
        /// <param name="value">翻译</param>
        /// <returns>返回是否添加成功</returns>
        public bool AddTranslation(string key, string value)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
            {
                TLogTool.Error("Key值或Value值不能为Null");
                return false;
            }

            if (_lanTranslation.ContainsKey(key))
            {
                TLogTool.Info(key + "已经添加");
                return false;
            }

            _lanTranslation.Add(key, value);
            return true;
        }

        /// <summary>
        /// 根据关键词移除翻译
        /// </summary>
        /// <param name="key">关键词</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveTranslation(string key)
        {
            if (HasTranslation(key) == false) return false;

            return _lanTranslation.Remove(key);
        }
        #endregion

        #region Internal Func
        private void ParseTranslationJson(string jsonMsg)
        {
            Translation translation = TinyUtility.Json.ToObject<Translation>(jsonMsg);
            if (translation == null) return;
            _curLanguage = translation.Lan;
            _lanTranslation.Clear();
            for (int i = 0; i < translation.TransItems.Count; i++)
            {
                TranslationItem item = translation.TransItems[i];
                string key = item.Category + "." + item.Key;
                string value = item.Value;
                AddTranslation(key, value);
            }

            OnLanguageChanged?.Invoke();
            OnLanguageChangedLater?.Invoke();
        }

        private void LoadLocalizationFile(Language lan, string filePath)
        {
            if (TinyTool.Instance != null && TinyTool.Instance.TinyToolSetting != null)
            {
                LocalizationPathType pathType = TinyTool.Instance.TinyToolSetting.localizationPathType;

                string jsonMsg = string.Empty;
                string absolutefilePath = string.Empty;
                switch (pathType)
                {
                    case LocalizationPathType.Resources:
                        absolutefilePath = TinyUtility.Path.GetPathWithoutExtension(filePath);
                        TextAsset textAsset = _resourcesManager.LoadAsset<TextAsset>(absolutefilePath);
                        if (textAsset != null)
                            jsonMsg = textAsset.text;
                        else
                            TLogTool.Error("未找到：" + absolutefilePath);

                        if (_allTranslations.ContainsKey(lan) == false)
                            _allTranslations.Add(lan, jsonMsg);

                        ParseTranslationJson(jsonMsg);
                        break;
                    case LocalizationPathType.StreamingAssets:
                        absolutefilePath = TinyUtility.Path.GetStreamingAssetsPath() + filePath;
                        int index = -1;
                        index = absolutefilePath.LastIndexOf(".");
                        if (index < 0)
                            absolutefilePath = TinyUtility.Path.GetPathWithoutExtension(absolutefilePath) +
                                               ".json";

                        if (File.Exists(absolutefilePath))
                        {
                            //jsonMsg = File.ReadAllText(configPath);
                            //Android端File不能读取StreamingAssets里的文件，所以采用异步的方式读取文本
                            TinyUtility.File.LoadTextFileAsync(absolutefilePath, value =>
                            {
                                if (_allTranslations.ContainsKey(lan) == false)
                                    _allTranslations.Add(lan, value);

                                ParseTranslationJson(value);
                            });
                        }
                        else
                            TLogTool.Error("未找到配置表：" + absolutefilePath);

                        break;
                    case LocalizationPathType.Custom:
                        TLogTool.Info("使用自定义的方式加载，需要先调用SetLanTranslates方法来设置配置表");
                        break;
                }
            }
            else
            {
                TLogTool.Error("TinyTool.Instance 或 TinyToolSetting资源不能为Null");
            }
        }

        private Language GetSystemLan()
        {
            switch (Application.systemLanguage)
            {
                case UnityEngine.SystemLanguage.Afrikaans: return Language.Afrikaans;
                case UnityEngine.SystemLanguage.Arabic: return Language.Arabic;
                case UnityEngine.SystemLanguage.Basque: return Language.Basque;
                case UnityEngine.SystemLanguage.Belarusian: return Language.Belarusian;
                case UnityEngine.SystemLanguage.Bulgarian: return Language.Bulgarian;
                case UnityEngine.SystemLanguage.Catalan: return Language.Catalan;
                case UnityEngine.SystemLanguage.Chinese: return Language.ChineseSimplified;
                case UnityEngine.SystemLanguage.ChineseSimplified: return Language.ChineseSimplified;
                case UnityEngine.SystemLanguage.ChineseTraditional: return Language.ChineseTraditional;
                case UnityEngine.SystemLanguage.Czech: return Language.Czech;
                case UnityEngine.SystemLanguage.Danish: return Language.Danish;
                case UnityEngine.SystemLanguage.Dutch: return Language.Dutch;
                case UnityEngine.SystemLanguage.English: return Language.English;
                case UnityEngine.SystemLanguage.Estonian: return Language.Estonian;
                case UnityEngine.SystemLanguage.Faroese: return Language.Faroese;
                case UnityEngine.SystemLanguage.Finnish: return Language.Finnish;
                case UnityEngine.SystemLanguage.French: return Language.French;
                case UnityEngine.SystemLanguage.German: return Language.German;
                case UnityEngine.SystemLanguage.Greek: return Language.Greek;
                case UnityEngine.SystemLanguage.Hebrew: return Language.Hebrew;
                case UnityEngine.SystemLanguage.Hungarian: return Language.Hungarian;
                case UnityEngine.SystemLanguage.Icelandic: return Language.Icelandic;
                case UnityEngine.SystemLanguage.Indonesian: return Language.Indonesian;
                case UnityEngine.SystemLanguage.Italian: return Language.Italian;
                case UnityEngine.SystemLanguage.Japanese: return Language.Japanese;
                case UnityEngine.SystemLanguage.Korean: return Language.Korean;
                case UnityEngine.SystemLanguage.Latvian: return Language.Latvian;
                case UnityEngine.SystemLanguage.Lithuanian: return Language.Lithuanian;
                case UnityEngine.SystemLanguage.Norwegian: return Language.Norwegian;
                case UnityEngine.SystemLanguage.Polish: return Language.Polish;
                case UnityEngine.SystemLanguage.Portuguese: return Language.PortuguesePortugal;
                case UnityEngine.SystemLanguage.Romanian: return Language.Romanian;
                case UnityEngine.SystemLanguage.Russian: return Language.Russian;
                case UnityEngine.SystemLanguage.SerboCroatian: return Language.SerboCroatian;
                case UnityEngine.SystemLanguage.Slovak: return Language.Slovak;
                case UnityEngine.SystemLanguage.Slovenian: return Language.Slovenian;
                case UnityEngine.SystemLanguage.Spanish: return Language.Spanish;
                case UnityEngine.SystemLanguage.Swedish: return Language.Swedish;
                case UnityEngine.SystemLanguage.Thai: return Language.Thai;
                case UnityEngine.SystemLanguage.Turkish: return Language.Turkish;
                case UnityEngine.SystemLanguage.Ukrainian: return Language.Ukrainian;
                case UnityEngine.SystemLanguage.Unknown: return Language.Unspecified;
                case UnityEngine.SystemLanguage.Vietnamese: return Language.Vietnamese;
                default: return Language.Unspecified;
            }
        }
        #endregion
    }
}